/*
 * @Author: Black / 李来然
 * @Date: 2021-12-17 16:40:41
 * @LastEditors: Black / 李来然
 * @LastEditTime: 2022-01-26 13:16:59
 * @Description: 摄像头模块的 TS 重构
 */
import { ModsInstance } from "@/func/createMod";
import { BaseIO } from "./baseIO";
import { getModeFuncRet, RetResult } from "../tools/modHelper";
import { WindowOpt } from "@/func/modeFunc/takePictureStep";

// 相机设备的状态
type DeviceStatus =
  | "HEALTHY"
  | "HWERROR"
  | "OFFLINE"
  | "POWEROFF"
  | "NODEVICE"
  | "BUSY"
  | "USERERROR"
  | "FRAUDATTEMPT"
  | "POTENTIALFRAUD";

// 相机的记录媒介的状态
type MediaStatus = "OK " | "HIGH" | "FULL" | "NOTSUPP" | "UNKNOWN";

// 相机的状态
type CamerasStatus = "NOTSUPP" | "OK" | "INOP" | "UNKNOWN";

type ResetRet = "ResetComplete" | "DeviceError" | "FatalError";

export interface CamState {
  StDeviceStatus: DeviceStatus;
  StMediaStatus: MediaStatus;
  StCamerasStatus: CamerasStatus;
}

export interface CamCapability {}

type TakePictureRet =
  | "TakePictureSuccess"
  | "TakePictureEXSuccess"
  // 人脸识别摄像头（双目摄像头）检测不符合要求
  | "MediaThreshold"
  | "FatalError"
  | "Timeout"
  | "DeviceError"
  // 保存图片时字符串太长有其他的错误
  | "InvalidData";

type StartDisplyRet = "DisplayStarted" | "DeviceError" | "FatalError";

type StopDisplyRet = "DisplayStoped" | "DeviceError" | "FatalError";

export class Cam extends BaseIO<CamState, CamCapability> {
  private isNeedWaitCancel: boolean = false;
  constructor(modName: keyof ModsInstance, mod: any) {
    super(modName, mod);
  }

  /**
   * 拍照
   * @param {string} strPath 需要添加到图片上的文字和图片保存完整路径。如：;c:\\eastcom\\abwoa\\bin\\cust.jpg
   * @param {string} ID ROOM|PERSON|EXITSLOT|EXTRA|HIGHCAMERA 摄像头ID
   * @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
   * @return {String} return.mod 模块名
   * @return {String} return.ret 事件 <br> sgnTakePicture - 拍照成功 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br> InvalidData - 无效数据 <br>
   * @return {Array} return.param - 事件参数 无
   */
  TakePicture(ID: string, cameraData: string) {
    Trace(EC_INFO, "-->Cam:TakePicture");
    this.setCurrentMethod("TakePicture");
    this.removeMethodBindEvt("TakePicture");
	this.isNeedWaitCancel = true;
    return new Promise<RetResult<TakePictureRet>>((resolve, reject) => {
      const TakePictureSuccess = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePicture TakePictureSuccess");
        resolve(getModeFuncRet(this.modName, "TakePictureSuccess", args));
      };
      const MediaThreshold = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePicture MediaThreshold");
        resolve(getModeFuncRet(this.modName, "MediaThreshold", args));
      };
      const Timeout = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePicture Timeout");
        resolve(getModeFuncRet(this.modName, "Timeout", args));
      };
      const FatalError = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePicture FatalError");
        resolve(getModeFuncRet(this.modName, "FatalError", args));
      };
      const DeviceError = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePicture DeviceError");
        resolve(getModeFuncRet(this.modName, "DeviceError", args));
      };
      const InvalidData = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePicture InvalidData");
        resolve(getModeFuncRet(this.modName, "InvalidData", args));
      };

      // 事件注册
      this.add("TakePictureSuccess", TakePictureSuccess);
      this.add("MediaThreshold", MediaThreshold);
      this.add("Timeout", Timeout);
      this.add("FatalError", FatalError);
      this.add("DeviceError", DeviceError);
      this.add("InvalidData", InvalidData);

      this.mod.TakePicture(ID, cameraData, "", (ret: string) => {
        if (parseInt(ret) !== 0) {
          Trace(EC_INFO, "<--Cam:TakePicture ret=" + ret);
          resolve(getModeFuncRet(this.modName, "FatalError"));
        }
      });
    }).then((value) => {
	  this.isNeedWaitCancel = true;
      this.removeMethodBindEvt("TakePicture");
      return value;
    });
  }
  /**
   * 拍照
   * @param {string} strPath 需要添加到图片上的文字和图片保存完整路径。如：;c:\\eastcom\\abwoa\\bin\\cust.jpg
   * @param {string} ID ROOM|PERSON|EXITSLOT|EXTRA|HIGHCAMERA 摄像头ID
   * @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
   * @return {String} return.mod 模块名
   * @return {String} return.ret 事件 <br> sgnTakePicture - 拍照成功 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br> InvalidData - 无效数据 <br>
   * @return {Array} return.param - 事件参数 无
   */
  TakePictureEX(
    ID: string,
    cameraData: string = "",
    pictureFile: string,
    timeout: number = 0
  ) {
    Trace(EC_INFO, "-->Cam:TakePicture");
    this.setCurrentMethod("TakePictureEX");
    this.removeMethodBindEvt("TakePictureEX");
    return new Promise<RetResult<TakePictureRet>>((resolve, reject) => {
      const TakePictureEXSuccess = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePictureEX TakePictureEXSuccess");
        resolve(getModeFuncRet(this.modName, "TakePictureEXSuccess", args));
      };
      const MediaThreshold = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePictureEX MediaThreshold");
        resolve(getModeFuncRet(this.modName, "MediaThreshold", args));
      };
      const Timeout = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePictureEX Timeout");
        resolve(getModeFuncRet(this.modName, "Timeout", args));
      };
      const FatalError = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePictureEX FatalError");
        resolve(getModeFuncRet(this.modName, "FatalError", args));
      };
      const DeviceError = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePictureEX DeviceError");
        resolve(getModeFuncRet(this.modName, "DeviceError", args));
      };
      const InvalidData = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:TakePictureEX InvalidData");
        resolve(getModeFuncRet(this.modName, "InvalidData", args));
      };

      // 事件注册
      this.add("TakePictureEXSuccess", TakePictureEXSuccess);
      this.add("MediaThreshold", MediaThreshold);
      this.add("Timeout", Timeout);
      this.add("FatalError", FatalError);
      this.add("DeviceError", DeviceError);
      this.add("InvalidData", InvalidData);

      this.mod.TakePictureEX(
        ID,
        cameraData,
        pictureFile,
        timeout,
        (ret: string) => {
          if (parseInt(ret) !== 0) {
            Trace(EC_INFO, "<--Cam:TakePictureEX ret=" + ret);
            resolve(getModeFuncRet(this.modName, "FatalError"));
          }
        }
      );
    }).then((value) => {
      this.removeMethodBindEvt("TakePictureEX");
      return value;
    });
  }

  /**
   * 打开摄影面板
   * @param {string} CameraID ROOM|PERSON|EXITSLOT|EXTRA|HIGHCAMERA 摄像头ID
   * @param {element} e  html DOM 元素
   * @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
   * @return {String} return.mod 模块名
   * @return {String} return.ret 事件 <br> DisplayStarted - 预览框打开成功 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br>
   * @return {Array} return.param - 事件参数 无
   */
  StartDisplay(CameraID: string, windowOpt: WindowOpt) {
    Trace(
      EC_INFO,
      `-->Cam:StartDisplay:${CameraID},${JSON.stringify(windowOpt)}`
    );
    this.setCurrentMethod("StartDisplay");
    this.removeMethodBindEvt("StartDisplay");
    // 动态计算面板位置,获取dom后计算
    const PositionX = windowOpt.x; // x
    const PositionY = windowOpt.y; // y

    const Width = windowOpt.width; // width
    const High = windowOpt.height; // height

    return new Promise<RetResult<StartDisplyRet>>((resolve, reject) => {
      const DisplayStarted = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:StartDisplay DisplayStarted");
        resolve(getModeFuncRet(this.modName, "DisplayStarted", args));
      };
      const DeviceError = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:StartDisplay DeviceError");
        resolve(getModeFuncRet(this.modName, "DeviceError", args));
      };
      const FatalError = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:StartDisplay FatalError");
        resolve(getModeFuncRet(this.modName, "FatalError", args));
      };

      this.add("DisplayStarted", DisplayStarted);
      this.add("DeviceError", DeviceError);
      this.add("FatalError", FatalError);

      this.mod.StartDisplay(
        CameraID,
        PositionX,
        PositionY,
        Width,
        High,

        (ret: string) => {
          console.log(CameraID, PositionX, PositionY, Width, High);
          if (parseInt(ret) !== 0) {
            Trace(EC_INFO, "<--Cam:StartDisplay ret=" + ret);
            resolve(getModeFuncRet(this.modName, "FatalError"));
          }
        }
      );
    }).then((value) => {
      this.removeMethodBindEvt("StartDisplay");
      return value;
    });
  }

  /**
   * 关闭摄影面板
   * @param {string} CameraID ROOM|PERSON|EXITSLOT|EXTRA|HIGHCAMERA 摄像头ID
   * @returns {Promise<json>} - {mod:this.modName, ret: '', param: arg}
   * @return {String} return.mod 模块名
   * @return {String} return.ret 事件 <br> DisplayStoped - 预览框关闭成功 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br>
   * @return {Array} return.param - 事件参数 无
   */
  StopDisplay(CameraID: string, isNeedCancel: boolean = false) {
    Trace(EC_INFO, "-->Cam:StopDisplay");
    this.setCurrentMethod("StopDisplay");
    this.removeMethodBindEvt("StopDisplay");
    let FatalErrorCount = 0;
    let JumpFatalErrorCount = 0;
    return new Promise<RetResult<StopDisplyRet>>((resolve, reject) => {
      const DisplayStoped = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:StopDisplay DisplayStoped");
        resolve(getModeFuncRet(this.modName, "DisplayStoped", args));
      };
      const DeviceError = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:StopDisplay DeviceError");
        resolve(getModeFuncRet(this.modName, "DeviceError", args));
      };
      const FatalError = (...args: any[]) => {
        ++FatalErrorCount;
        if (FatalErrorCount > JumpFatalErrorCount) {
          Trace(EC_INFO, "<--Cam:StopDisplay FatalError");
          resolve(getModeFuncRet(this.modName, "FatalError", args));
        }
      };

      this.add("DisplayStoped", DisplayStoped);
      this.add("DeviceError", DeviceError);
      this.add("FatalError", FatalError);

      if (isNeedCancel && this.isNeedWaitCancel) {
        JumpFatalErrorCount = 1;
        this.CancelAllRequest();
      }

      this.mod.StopDisplay(CameraID, (ret: string) => {
        if (parseInt(ret) !== 0) {
          Trace(EC_INFO, "<--Cam:StopDisplay ret=" + ret);
          resolve(getModeFuncRet(this.modName, "FatalError"));
        }
      });
    }).then((value) => {
      this.removeMethodBindEvt("StopDisplay");
      return value;
    });
  }

  /**
   * 指令取消
   * @return Promise<number> 0 成功，-1 失败
   */
  CancelAllRequest() {
    this.setCurrentMethod("CancelAllRequest");
    this.removeMethodBindEvt("CancelAllRequest");
    return new Promise((resolve, reject) => {
      this.mod.CancelAllRequest((ret: any) => {
        resolve(ret);
      });
    }).then((value) => {
      this.removeMethodBindEvt("CancelAllRequest");
      return value;
    });
  }

  // 复位动作
  Reset() {
    Trace(EC_INFO, "-->Cam:Reset");
    this.setCurrentMethod("Reset");
    this.removeMethodBindEvt("Reset");
    return new Promise<RetResult<ResetRet>>((resolve, reject) => {
      const DisplayStoped = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:StopDisplay DisplayStoped");
        resolve(getModeFuncRet(this.modName, "ResetComplete", args));
      };
      const DeviceError = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:StopDisplay DeviceError");
        resolve(getModeFuncRet(this.modName, "DeviceError", args));
      };
      const FatalError = (...args: any[]) => {
        Trace(EC_INFO, "<--Cam:StopDisplay FatalError");
        resolve(getModeFuncRet(this.modName, "FatalError", args));
      };

      this.add("DisplayStoped", DisplayStoped);
      this.add("DeviceError", DeviceError);
      this.add("FatalError", FatalError);

      this.mod.Reset((ret: string) => {
        if (parseInt(ret) !== 0) {
          Trace(EC_INFO, "<--Cam:Reset ret=" + ret);
          resolve(getModeFuncRet(this.modName, "FatalError"));
        }
      });
    }).then((value) => {
      this.removeMethodBindEvt("Reset");
      return value;
    });
  }
}
